`timescale 1ns / 1ps
include "defines.v";
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    14:51:04 11/19/2020 
// Design Name: 
// Module Name:    DM 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module DM(
	 input [31:0] WPC,
    input [13:0] memAddr,
    input [31:0] RD2,
    input memWrite,
	 input isSigned,
	 input [1:0]funType,
    input clk,
    input reset,
    output [31:0] memData
    );
	 integer i;
	 reg [7:0]ram[0:116384];
	 wire [31:0]memAddress;
	 reg [31:0] storeData;
	 wire [1:0]offset;
	 reg [31:0]temp;
	 assign memAddress = {{18'd0},memAddr[13:2],{2'd0}};
	 assign offset = memAddr[1:0];
	 initial
	 begin
		for(i = 0;i < 116384;i = i + 1)
				ram[i] = 0;
		temp = 0;
		storeData = 0;
	 end
	 
	 always @*
	 begin
		case (funType)
			`WORD:
			begin
				storeData = RD2;
			end
			`HALFWORD:
			begin
				if(~offset[1])
					storeData = {ram[memAddress+3],ram[memAddress+2],RD2[15:0]};
				else
					storeData = {RD2[15:0],ram[memAddress+1],ram[memAddress]};					
			end
			`BYTE:
			begin
				case (offset)
				3:
					storeData = {RD2[7:0],ram[memAddress+2],ram[memAddress+1],ram[memAddress]};
				2:
					storeData = {ram[memAddress+3],RD2[7:0],ram[memAddress+1],ram[memAddress]};
				1:
					storeData = {ram[memAddress+3],ram[memAddress+2],RD2[7:0],ram[memAddress]};
				0:
					storeData = {ram[memAddress+3],ram[memAddress+2],ram[memAddress+1],RD2[7:0]};
				endcase
			end
		endcase
	 end
	 
	 always @(posedge clk)
	 begin
		if(reset)
		begin
			for(i = 0;i < 16384;i = i + 1)
				ram[i] = 0;
		end
		else begin
			if (memWrite)
			begin
				case (funType)
					`WORD:
					begin
						ram[memAddr+3] = RD2[31:24];
						ram[memAddr+2] = RD2[23:16];
						ram[memAddr+1] = RD2[15:8];
						ram[memAddr] = RD2[7:0];
					end
					`HALFWORD:
					begin
						ram[memAddr+1] = RD2[15:8];
						ram[memAddr] = RD2[7:0];
					end
					`BYTE:
					begin
						ram[memAddr] = RD2[7:0];
					end
				endcase 
				$display("%d@%h: *%h <= %h", $time, WPC, memAddress, storeData);
			end		
		end
	 end
	
	 always @*
	 case (funType)
		`WORD:
		begin
			temp[31:24] = ram[memAddr+3];
			temp[23:16] = ram[memAddr+2] ;
			temp[15:8] = ram[memAddr+1];
			temp[7:0] = ram[memAddr];
		end
		`HALFWORD:
		begin
			temp[31:24] = 0;
			temp[23:16] = 0;
			temp[15:8] = ram[memAddr+1];
			temp[7:0] = ram[memAddr];
		end
		`BYTE:
		begin
			temp[31:24] = 0;
			temp[23:16] = 0;
			temp[15:8] = 0;
			temp[7:0] = ram[memAddr];
		end		
	 endcase
	 DM_Extender extender(
		.isSigned(isSigned),
		.memData(temp),
		.type(funType),
		.outData(memData)
		);
endmodule
